/****************************************************************************
**
**	$Header: $
**
**	Description : 
**
**		XML-based application profile storage, based on code published by 
**		Emilio Guijarro Cameros at www.codeproject.com
**
****************************************************************************/
#include "XMLProfile.h"

#pragma comment(lib, "comsuppw.lib")
/****************************************************************************
**
**	CXMLProfile::CXMLProfile() -- [CTOR]
**
*/
CXMLProfile::CXMLProfile(
	LPCTSTR	pstrXMLFile) : m_pXMLDoc(NULL)
{		
if (GetVersion() < 0x80000000) 
	{
	TCHAR	szProfilesDir[MAX_PATH];

	SHGetSpecialFolderPath(NULL, szProfilesDir, CSIDL_LOCAL_APPDATA, TRUE);
	m_bstrFile = _bstr_t(szProfilesDir) + _bstr_t("\\") + _bstr_t(pstrXMLFile) + _bstr_t(".xml");		
	}
else
	m_bstrFile = _bstr_t(pstrXMLFile);
}	/* end of CXMLProfile::CXMLProfile() */
/****************************************************************************
**
**	CXMLProfile::Put() --
**
*/
bool 
CXMLProfile::Put(
	LPCTSTR	pstrSection, 
	LPCTSTR	pstrEntry, 
	int		nValue) 
{
bool			bOK = false;	
IXMLDOMNode *	pXMLNode = getEntry(pstrSection, pstrEntry);

if (pXMLNode)
	{
	WCHAR	wszTemp[255];

	_itow(nValue, wszTemp, 10);
	if (SUCCEEDED(pXMLNode->put_text(_bstr_t(wszTemp))))
		bOK = true;
	
	pXMLNode->Release();
	}

return bOK;
}	/* end of CXMLProfile::Put() */
/****************************************************************************
**
**	CXMLProfile::Put() --
**
*/
bool 
CXMLProfile::Put(
	LPCTSTR	pstrSection, 
	LPCTSTR	pstrEntry, 
	RECT &	rValue) 
{
bool			bOK = false;	
IXMLDOMNode *	pXMLNode = getEntry(pstrSection, pstrEntry);

if (pXMLNode)
	{
	TCHAR	wszTmp[255];
	
	(void) _snprintf(	wszTmp, 255, 
						"%ld %ld %ld %ld", 
						rValue.top, rValue.left, rValue.bottom, rValue.right);
						
	if (SUCCEEDED(pXMLNode->put_text(_bstr_t(wszTmp))))
		bOK = true;
	
	pXMLNode->Release();
	}
	
return bOK;
}	/* end of CXMLProfile::Put() */
/****************************************************************************
**
**	CXMLProfile::Put() --
**
*/
bool 
CXMLProfile::Put(
	LPCTSTR	pstrSection, 
	LPCTSTR	pstrEntry, 
	LPCTSTR	pszValue) 
{
bool			bOK = false;	
IXMLDOMNode *	pXMLNode = getEntry(pstrSection, pstrEntry);

if (pXMLNode && pszValue)
	{
	if (SUCCEEDED(pXMLNode->put_text(_bstr_t(pszValue))))
		bOK = true;
	pXMLNode->Release();
	}
	
return bOK;
}	/* end of CXMLProfile::Put() */
/****************************************************************************
**
**	CXMLProfile::Get() --	
**
*/
int 
CXMLProfile::Get(
	LPCTSTR	pstrSection, 
	LPCTSTR pstrEntry, 
	int		nDefault) 
{
int				nResult = nDefault;
IXMLDOMNode *	pXMLNode = getEntry(pstrSection, pstrEntry);

if (pXMLNode)
	{
	BSTR	bstrContent = NULL;
		
	pXMLNode->get_text(&bstrContent);

	if (bstrContent && _bstr_t(bstrContent) != _bstr_t("")) 
		{
		LPSTR	pszContent = _com_util::ConvertBSTRToString(bstrContent);

		if (pszContent)
			{
			nResult = atoi(pszContent);
			delete [] pszContent;
			}
		}
	else	// couldn't find it?
		{
		IXMLDOMNode *	pXMLNodeParent;
			
		pXMLNode->get_parentNode(&pXMLNodeParent);
		pXMLNodeParent->removeChild(pXMLNode, NULL);
		pXMLNodeParent->Release();
		}
		
	pXMLNode->Release();
	}

return nResult;
}	/* end of CXMLProfile::Get();
/****************************************************************************
**
**	CXMLProfile::Get() --	
**
*/
RECT & 
CXMLProfile::Get(
	LPCTSTR	pstrSection, 
	LPCTSTR pstrEntry, 
	RECT &	rValue,
	RECT *	prDefault) 
{
IXMLDOMNode *	pXMLNode = getEntry(pstrSection, pstrEntry);

if (prDefault == NULL)
	(void) ::SetRectEmpty(&rValue);
else
	rValue = *prDefault;
	
if (pXMLNode)
	{
	BSTR	bstrContent = NULL;
		
	pXMLNode->get_text(&bstrContent);

	if (bstrContent && _bstr_t(bstrContent) != _bstr_t("")) 
		{
		LPSTR	pszContent = _com_util::ConvertBSTRToString(bstrContent);

		if (pszContent)
			{
			(void) sscanf(pszContent, "%ld %ld %ld %ld", 
							&rValue.top, &rValue.left, &rValue.bottom, &rValue.right);
			delete [] pszContent;
			}
		}
	else	// couldn't find it?
		{
		IXMLDOMNode *	pXMLNodeParent;
			
		pXMLNode->get_parentNode(&pXMLNodeParent);
		pXMLNodeParent->removeChild(pXMLNode, NULL);
		pXMLNodeParent->Release();
		}
		
	pXMLNode->Release();
	}

return rValue;
}	/* end of CXMLProfile::Get();
/****************************************************************************
**
**	CXMLProfile::Get() --	
**
*/
LPSTR
CXMLProfile::Get(
	LPCTSTR	pstrSection, 
	LPCTSTR	pstrEntry, 
	LPSTR	pszBuffer, 
	UINT	uBufferSize, 
	LPCSTR	pstrDefault)
{
IXMLDOMNode *	pXMLNode = getEntry(pstrSection, pstrEntry);

::ZeroMemory(pszBuffer, uBufferSize);

if (pXMLNode)
	{
	BSTR	bstrContent = NULL;
	
	pXMLNode->get_text(&bstrContent);

	if (bstrContent && _bstr_t(bstrContent) != _bstr_t("")) 
		{
		LPSTR	pszContent = _com_util::ConvertBSTRToString(bstrContent);

		if (pszContent)
			{
			(void) strncpy(pszBuffer, pszContent, uBufferSize);
			delete [] pszContent;
			}
		}
	else	// couldn't find it?
		{
		IXMLDOMNode *	pXMLNodeParent;
			
		pXMLNode->get_parentNode(&pXMLNodeParent);
		pXMLNodeParent->removeChild(pXMLNode, NULL);
		pXMLNodeParent->Release();
		
		(void) strncpy(pszBuffer, pstrDefault, uBufferSize);
		}
		
	pXMLNode->Release();
	}
else
	(void) strncpy(pszBuffer, pstrDefault, uBufferSize);

return LPSTR(pszBuffer);
}

IXMLDOMNode * CXMLProfile::getSection(LPCTSTR pstrSection)
{
	IXMLDOMElement* base, *element;
	IXMLDOMNode* nSec, *nResult;
	_bstr_t szName;
	bool bSecFound = false, bEntryFound = false;

	m_pXMLDoc->get_documentElement(&base);
	
	for(base->get_firstChild(&nSec); nSec != NULL; nSec->get_nextSibling(&nSec)) {
		nSec->get_baseName(szName.GetAddress());

		if(szName == _bstr_t(pstrSection)) {
			nResult = nSec;
			break;
		}
	}

	if(nSec == NULL) {
		m_pXMLDoc->createElement(_bstr_t(pstrSection), &element);
		base->appendChild(element, &nSec);
		element->Release();
		nResult = nSec;
	}

	base->Release();
	
	return nResult;
}

IXMLDOMNode * CXMLProfile::getEntry(LPCTSTR pstrSection, LPCTSTR pstrEntry)
{
	IXMLDOMElement* base, *element;
	IXMLDOMNode* nSec, *nEntry, *nResult;
	_bstr_t szName;

	m_pXMLDoc->get_documentElement(&base);
	
	for(base->get_firstChild(&nSec); nSec != NULL; nSec->get_nextSibling(&nSec)) {
		nSec->get_baseName(szName.GetAddress());

		if(szName == _bstr_t(pstrSection)) {
			for(nSec->get_firstChild(&nEntry); nEntry != NULL; nEntry->get_nextSibling(&nEntry)) {
				nEntry->get_baseName(szName.GetAddress());

				if(szName == _bstr_t(pstrEntry)) {
					nResult = nEntry;				
					break;
				}
			}

			if(nEntry == NULL) {
				m_pXMLDoc->createElement(_bstr_t(pstrEntry), &element);
				nSec->appendChild(element, &nEntry);
				element->Release();
				nResult = nEntry;
			}
			nSec->Release();
			break;
		}
	}

	if(nSec == NULL) {
		m_pXMLDoc->createElement(_bstr_t(pstrSection), &element);
		base->appendChild(element, &nSec);
		element->Release();
		m_pXMLDoc->createElement(_bstr_t(pstrEntry), &element);
		nSec->appendChild(element, &nEntry);
		element->Release();
		nResult = nEntry;
	}
	
	base->Release();

	return nResult;
}

bool CXMLProfile::Load(
	LPCTSTR	pstrRootTag)
{
if (m_pXMLDoc != NULL)
	return false;

if (SUCCEEDED(CoInitialize(NULL)) && 
	SUCCEEDED(CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&m_pXMLDoc)))
	{
	VARIANT_BOOL bIgnored;

	if (FAILED(m_pXMLDoc->load(_variant_t(m_bstrFile), &bIgnored)))
		return false;
	}	

IXMLDOMElement *	base;
	
m_pXMLDoc->get_documentElement(&base);

if (base == NULL) 
	{
	m_pXMLDoc->createElement(_bstr_t(pstrRootTag), &base);
	m_pXMLDoc->appendChild(base, NULL);
	}

return true;
}	/* end of CXMLProfile::Load() */
/****************************************************************************
**
**	$History: XMLProfile.cpp $
**
**	-------------------------------------------------------------------------
**
**	End of XMLProfile.cpp
**
****************************************************************************/
